//
// Created by 11510 on 2024/7/8.
//

#ifndef REACTOR_TCPCONNECTION_H
#define REACTOR_TCPCONNECTION_H

#include "SocketIO.h"
#include "Socket.h"
#include "InetAddress.h"
#include <sstream>
#include <memory>
#include <functional>

class TcpConnection : public std::enable_shared_from_this<TcpConnection> {
public:
    using TcpConnectionPtr = std::shared_ptr<TcpConnection>;
    using TcpConnectionCallback = std::function<void(const TcpConnectionPtr &)>;

private:
    SocketIO _socketIO;

//    调试用，后期可删除
    Socket _sock;
    InetAddress _localAddr;
    InetAddress _peerAddr;

    TcpConnectionCallback _onNewConnectionCallback;
    TcpConnectionCallback _onMessageCallback;
    TcpConnectionCallback _onCloseCallback;

public:
    explicit TcpConnection(int fd) :
            _socketIO(fd),
            _sock(fd),
            _localAddr(getLocalAddr()),
            _peerAddr(getPeerAddr()) {}

    ~TcpConnection() = default;

    std::string receive() {
        char buf[(1 << 16) - 1];
        ::memset(buf, 0, sizeof buf);
        _socketIO.readLine(buf, sizeof buf);

        return std::string(buf);
    }

    void send(const std::string &msg) {
        _socketIO.writen(msg.c_str(), msg.size());
    }

    std::string toString() {
        std::ostringstream oss;
        oss << _localAddr.ip() << ":"
            << _localAddr.port() << "---->"
            << _peerAddr.ip() << ":"
            << _peerAddr.port();

        return oss.str();
    }


    void setOnNewConnectionCallback(TcpConnectionCallback &onNewConnectionCallback) {
        _onNewConnectionCallback = onNewConnectionCallback;
    }

    void setOnMessageCallback(TcpConnectionCallback &onMessageCallback) {
        _onMessageCallback = onMessageCallback;
    }

    void setOnCloseCallback(TcpConnectionCallback &onCloseCallback) {
        _onCloseCallback = onCloseCallback;
    }

    void handleOnNewConnectionCallback() {
        if (_onNewConnectionCallback) {
            /**
             * 如果这里传shared_ptr<TcpConnection>(this)
             * 那么匿名对象和本类的对象的智能指针会同时托管同一片空间，会造成double free
             */
            _onNewConnectionCallback(shared_from_this());
        }
    }

    void handleOnMessageCallback() {
        if (_onMessageCallback) {
            _onMessageCallback(shared_from_this());
        }
    }

    void handleOnCloseCallback() {
        if (_onCloseCallback) {
            _onCloseCallback(shared_from_this());
        }
    }

    bool isClosed() const {
        char buf[1 << 3];
        ssize_t bytes = ::recv(_sock.getFileDescriptor(), buf, sizeof buf, MSG_PEEK);
//        WARNING: 对方有可能正常关闭，也可能异常退出
//        printf("bytes = %d\n", bytes);
        return (bytes == 0) || (bytes == -1);
    }


private:
    /* 获取本端与对端的IP地址 */
    InetAddress getLocalAddr() {
        struct sockaddr_in addr;
        socklen_t len = sizeof(struct sockaddr);

        //获取本端地址的函数getsockname
        int ret = getsockname(_sock.getFileDescriptor(), (struct sockaddr *) &addr, &len);
        if (-1 == ret) {
            perror("getsockname");
        }

        return InetAddress(addr);
    }

    InetAddress getPeerAddr() {
        struct sockaddr_in addr;
        socklen_t len = sizeof(struct sockaddr);
        //获取对端地址的函数getpeername
        int ret = getpeername(_sock.getFileDescriptor(), (struct sockaddr *) &addr, &len);
        if (-1 == ret) {
            perror("getpeername");
        }

        return InetAddress(addr);
    }
};


#endif //REACTOR_TCPCONNECTION_H
